<template>
  <div class="my-spin" :class="wrapperClasses">
    <div v-if="loading && isDelayOver" class="my-spin__loading" :class="spinClasses">
      <slot name="dot">
        <span class="my-spin__dot">
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
      </span>
      </slot>

      <div class="my-spin__text">
        <slot name="text">{{tip}}</slot>
      </div>
    </div>
    <div v-if="$slots.default" class="my-spin__container" :class="containerClasses">
      <slot></slot>
    </div>
  </div>
</template>


<script>
export default {
  name: 'index',
  /**
   * 属性参数
   * @member props
   * @property {string} [size=default]  组件大小，可选值为 small default large
   * @property {number} [delay=100] 延迟显示加载效果的时间（防止闪烁）
   * @property {string} [tip] 当作为包裹元素时，可以自定义描述文案
   * @property {boolean} [loading=false] 是否为加载中状态
   * @property {boolean} [fit=false] 充满父容器
   */
  props: {
    // 组件大小，可选值为 small default large
    size: {
      type: String,
      default: 'default',
      validator(val) {
        return ['default', 'large', 'small'].includes(val)
      }
    },
    // 延迟显示加载效果的时间（防止闪烁）
    delay: {
      type: Number,
      default: 100
    },
    // 当作为包裹元素时，可以自定义描述文案
    tip: String,

    // 是否为加载中状态
    loading: Boolean,
    // 充满父容器
    fit: Boolean
  },
  data() {
    this.timerId = null
    return {
      isDelayOver: false
    }
  },
  watch: {
    loading: {
      immediate: true,
      handler(val) {
        val && this.setupLoading()
      }
    }
  },
  computed: {
    spinClasses() {
      return {
        [`is-${this.size}`]: !!this.size
      }
    },
    wrapperClasses() {
      return {
        'my-spin--nested': !!this.$slots.default,
        'is-fit': this.fit
      }
    },
    containerClasses() {
      return {
        'is-blur': (this.loading && this.isDelayOver)
      }
    }
  },
  methods: {
    setupLoading() {
      clearTimeout(this.timerId)
      this.isDelayOver = false
      if (this.delay > 0) {
        this.timerId = setTimeout(() => {
          this.isDelayOver = true
        }, this.delay)
      } else {
        this.isDelayOver = true
      }
    }
  },
  beforeDestroy() {
    clearTimeout(this.timerId)
  }
}
</script>

<style lang="less">
@-webkit-keyframes spinMove{
  to{
    opacity:1
  }
}
@keyframes spinMove{
  to{
    opacity:1
  }
}
@-webkit-keyframes spinRotate{
  to{
    -webkit-transform:rotate(405deg);
    transform:rotate(405deg)
  }
}
@keyframes spinRotate{
  to{
    -webkit-transform:rotate(405deg);
    transform:rotate(405deg)
  }
}
.my-spin{
  display:inline-block;
  vertical-align:middle
}
.my-spin__loading{
  -webkit-box-sizing:border-box;
  box-sizing:border-box;
  display:inline-block;
  text-align:center
}
.my-spin__loading.is-large .my-spin__dot{
  font-size:40px
}
.my-spin__loading.is-large i{
  width:20px;
  height:20px
}
.my-spin__loading.is-large .my-spin__text{
  font-size:1rem;
  padding-top:5px
}
.my-spin__loading.is-small .my-spin__dot{
  font-size:15px
}
.my-spin__loading.is-small i{
  width:7.5px;
  height:7.5px
}
.my-spin__loading.is-small .my-spin__text{
  font-size:1rem
}
.my-spin__dot{
  position:relative;
  display:inline-block;
  width:1em;
  height:1em;
  font-size:22px;
  -webkit-transform:rotate(45deg);
  transform:rotate(45deg);
  -webkit-animation:spinRotate 1.2s linear infinite;
  animation:spinRotate 1.2s linear infinite
}
.my-spin__dot-item{
  position:absolute;
  display:block;
  width:10px;
  height:10px;
  background-color:#1890ff;
  border-radius:100%;
  -webkit-transform:scale(.75);
  transform:scale(.75);
  -webkit-transform-origin:50% 50%;
  transform-origin:50% 50%;
  opacity:.3;
  -webkit-animation:spinMove 1s linear infinite alternate;
  animation:spinMove 1s linear infinite alternate
}
.my-spin__dot-item:first-child{
  left:0;
  top:0
}
.my-spin__dot-item:nth-child(2){
  top:0;
  right:0;
  -webkit-animation-delay:.4s;
  animation-delay:.4s
}
.my-spin__dot-item:nth-child(3){
  right:0;
  bottom:0;
  -webkit-animation-delay:.8s;
  animation-delay:.8s
}
.my-spin__dot-item:nth-child(4){
  bottom:0;
  left:0;
  -webkit-animation-delay:1.2s;
  animation-delay:1.2s
}
.my-spin__text{
  color:#1890ff;
  font-size:1rem
}
.my-spin--nested{
  position:relative;
  display:block
}
.my-spin--nested .my-spin__loading{
  position:absolute;
  width:100%;
  height:100%;
  text-align:center;
  left:0;
  top:0;
  z-index:2;
  display:block
}
.my-spin--nested .my-spin__loading.is-large .my-spin__dot{
  margin:-20px
}
.my-spin--nested .my-spin__loading.is-large .my-spin__text{
  margin-top:20px;
  padding-top:15px
}
.my-spin--nested .my-spin__loading.is-small .my-spin__dot{
  margin:-7.5px
}
.my-spin--nested .my-spin__loading.is-small .my-spin__text{
  padding-top:5px;
  margin-top:7.5px
}
.my-spin--nested .my-spin__dot{
  position:absolute;
  top:50%;
  left:50%;
  margin:-10px;
  margin-top:-15px
}
.my-spin--nested .my-spin__text{
  position:absolute;
  width:100%;
  top:50%;
  margin-top:15px
}
.my-spin--nested .my-spin__container{
  width:100%
}
.my-spin--nested .my-spin__container:after{
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
  z-index:10;
  width:100%;
  height:100%;
  background:#fff;
  opacity:0;
  -webkit-transition:all .3s;
  transition:all .3s;
  content:"";
  pointer-events:none
}
.my-spin--nested .my-spin__container.is-blur{
  opacity:.5;
  overflow:hidden;
  clear:both;
  -webkit-user-select:none;
  -moz-user-select:none;
  -ms-user-select:none;
  user-select:none
}
.my-spin--nested .my-spin__container.is-blur:after{
  opacity:.4;
  pointer-events:auto
}
.my-spin.is-fit{
  height:100%;
  width:100%;
  position:relative;
  text-align:center
}
.my-spin.is-fit .my-spin__container{
  height:100%;
  text-align:left
}
.my-spin.is-fit .my-spin__loading{
  position:absolute;
  top:50%;
  -webkit-transform:translateY(-50%);
  transform:translateY(-50%)
}

</style>
